Skip to content

fix(upgrade): fall back to the installer when a native updater refuses - #130

Merged
ralyodio merged 3 commits into
mainfrom
fix/privacycode-upgrade
Jul 31, 2026
Merged

fix(upgrade): fall back to the installer when a native updater refuses#130
ralyodio merged 3 commits into
mainfrom
fix/privacycode-upgrade

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

moshcode upgrade left targets stranded on old versions:

■  opencode is installed to /home/anthony/.privacycode/bin/privacycode
●  Using method: unknown
■  Upgrade failed — Unknown installation method: unknown

opencode-family updaters decide how to update by recognising where the binary
was installed
. When they don't recognise the location they resolve unknown
and stop — every run, so the version never moves.

This isn't machine-specific luck. The same opencode upgrade reports
Using method: curl and upgrades cleanly where the install is one it knows,
and fails where it isn't — which is exactly what was observed: it worked on one
box and failed on another. A fork living under its own directory
(~/.privacycode/bin) hits it every time.

Fix

Fall back to the installer when a native updater fails. Installers are
idempotent and fetch the latest — they're already what an uninstalled target
runs, so this is reusing a path that's known good.

  • the fallback only exists where the updater is a different command, so it can
    never re-run the one that just failed (claude, codex, gemini are
    npm i -g, which is already the installer — those aren't retried)
  • it announces itself rather than silently retrying
  • privacycode loses its native updater outright: it's opencode's, pointed at
    a directory opencode doesn't know, so it can never work. No reason to burn a
    failed run rediscovering that each time.

runUpgrade gains an injectable runner so the retry is testable without
spawning real installers.

Verified

4 new tests, 10/10 in test/upgrade.test.mjs: the refusal→installer sequence
runs in that order and reports success from the fallback; a target whose
"updater" is already its installer is not retried; privacycode plans the
installer while plain opencode keeps its updater.

🤖 Generated with Claude Code

ralyodio and others added 2 commits July 31, 2026 04:46
…ater

`moshcode upgrade` asked privacycode to update itself, and it always refused:

  ■ opencode is installed to /home/anthony/.privacycode/bin/privacycode
  ● Using method: unknown
  ■ Upgrade failed — Unknown installation method: unknown

privacycode is an opencode derivative, so `privacycode upgrade` is opencode's
updater, and that updater picks its method by recognising where the binary
was installed. It knows opencode's own locations; it does not know this
fork's ~/.privacycode/bin, so it resolves `unknown` and stops before doing
anything. Nothing about the machine makes this intermittent — it can never
upgrade an install made by that installer.

Drop the native updater from the engine and let upgradeSpec fall through to
the installer, which is idempotent and fetches the latest. Plain opencode
keeps its updater: run against a real opencode install it reports
`Using method: curl` and upgrades cleanly.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`moshcode upgrade` left targets stranded on old versions:

  ● Using method: unknown
  ■ Upgrade failed — Unknown installation method: unknown

opencode-family updaters choose how to update by recognising where the binary
was installed. When they don't recognise the location they resolve `unknown`
and stop — the same on every run, so the target never moves. It is not
machine-specific luck: the same `opencode upgrade` reports `Using method:
curl` and succeeds where the install is one it knows, and fails where it
isn't. A fork living under its own directory hits this every time.

Try the installer when the native updater fails. Installers are idempotent
and fetch the latest, which is why they are already what an uninstalled
target runs. The fallback only exists where the updater is a different
command, so it can never repeat the one that just failed, and it says so
rather than retrying silently.

privacycode loses its native updater outright: it is opencode's, pointed at
~/.privacycode/bin, so it cannot ever work — no reason to spend a failed run
discovering that every time.

Adds an injectable runner to runUpgrade so the retry is testable without
spawning real installers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

vu1nz Security Review

0 finding(s) in PR #?

No security issues found.

@ralyodio ralyodio closed this Jul 31, 2026
The sweep over every entry with a native updater guarded itself with
`length >= 5`, which is a number that moves whenever an entry gains or loses
an updater — privacycode just lost one, and the sweep failed despite the
invariant it exists to protect still holding for all four that remain.

Assert what the guard is for instead: that at least one engine and at least
one tool are in the sweep, so neither code path can silently drop out of it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@ralyodio ralyodio reopened this Jul 31, 2026
@ralyodio
ralyodio marked this pull request as ready for review July 31, 2026 05:34
@ralyodio
ralyodio merged commit 03d33c7 into main Jul 31, 2026
3 checks passed
@ralyodio
ralyodio deleted the fix/privacycode-upgrade branch July 31, 2026 05:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant